﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;

using SharpNetwork;
using SharpNetwork.SimpleWebSocket;

namespace SharpBroadcast
{
    public class MediaDispatcher
    {
        public ConcurrentQueue<BufferData> Buffers { get; private set; }

        public List<object> Clients { get; private set; }

        private IMediaServer m_Server = null;
        private bool m_IsWorking = true;
        private Thread m_WorkerThread = null;
        private ManualResetEvent m_Watcher = null;

        public MediaDispatcher(IMediaServer server, List<object> clients)
        {
            m_IsWorking = true;
            m_Server = server;

            Clients = clients;

            Buffers = new ConcurrentQueue<BufferData>();
            
            m_Watcher = new ManualResetEvent(false);

            m_WorkerThread = new Thread(new ThreadStart(Dispatch));
            m_WorkerThread.Start();
        }

        private void Dispatch()
        {
            while (m_IsWorking)
            {
                try
                {
                    if (m_IsWorking)
                    {
                        m_Watcher.Reset();
                        m_Watcher.WaitOne();
                    }
                    else break;

                    BufferData buffer = null;
                    while (m_IsWorking && Buffers.TryDequeue(out buffer))
                    {
                        if (buffer != null && buffer.Length > 0)
                        {
                            List<object> list = new List<object>();
                            List<object> badlist = new List<object>();
                            lock (Clients)
                            {
                                list.AddRange(Clients);
                            }
                            foreach (var client in list)
                            {
                                Session session = client as Session;
                                if (session == null) continue;
                                if (session.GetState() > 0)
                                {
                                    try
                                    {
                                        session.Send(new WebMessage(buffer.Buffer, buffer.Length));
                                    }
                                    catch { badlist.Add(client); }
                                }
                                else badlist.Add(client);
                            }
                            foreach (var client in badlist)
                            {
                                if (m_Server != null) m_Server.RemoveClient(client);
                                Session session = client as Session;
                                if (session != null) session.Close();
                            }
                        }
                    }
                }
                catch { }
            }
        }

        public void Process()
        {
            try
            {
                if (m_IsWorking) m_Watcher.Set();
            }
            catch { }
        }

        public void Stop()
        {
            m_IsWorking = false;
            try { if (m_Watcher != null) m_Watcher.Set(); }
            catch { }
            try { if (m_WorkerThread != null) m_WorkerThread.Abort(); }
            catch { }
            m_WorkerThread = null;
        }
    }

    public class BufferData
    {
        public byte[] Buffer { get; private set; }
        public int Length { get; private set; }

        public BufferData(byte[] buffer, int length)
        {
            Buffer = buffer;
            Length = length;
        }
    }
}
